using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace SteeringBehaviors
{
    public class Carrier : Ship
    {
        #region PUBLIC CONSTANTS

        public enum SHIPTYPES : int { FIGHTER, SCOUT, WORKER };
        public enum QUEUESTATUS : int { EMPTY, BUILDING, SHIPREADY };

        #endregion

        #region PRIVATE MEMBERS

        bool goToPointOfInterest;
        int maxQueue;
        double shipBuildTime;
        double buildTimer;
        Microsoft.DirectX.Vector3 pointOfInterest;
        BaseObject POI;
        Queue<ShipOrder> buildQueue;

        #endregion

        #region PROPERTIES

        /// <summary>
        /// If true then this carrier will travel to the position given by the PointOfInterest property.
        /// </summary>
        public bool GoToPointOfInterest
        {
            get { return goToPointOfInterest; }
            //set { goToPointOfInterest = value; }
        }

        /// <summary>
        /// A Vector3 object that represents a point of interest for this carrier
        /// </summary>
        public Microsoft.DirectX.Vector3 PointOfInterest
        {
            get { return pointOfInterest; }
            set
            {
                pointOfInterest = value;
                POI.Position = value;
                goToPointOfInterest = true;
                Velocity += GetForward() * MaxSpeed;
            }
        }

        /// <summary>
        /// State of the build queue for this carrier
        /// </summary>
        public QUEUESTATUS QueueStatus
        {
            get
            {
                QUEUESTATUS returnval = QUEUESTATUS.EMPTY;
                if (buildQueue.Count > 0)
                {
                    if (buildTimer < ShipBuildTime)
                        returnval = QUEUESTATUS.BUILDING;
                    else
                        returnval = QUEUESTATUS.SHIPREADY;
                }
                return returnval;
            }
        }

        /// <summary>
        /// The amount of time required to build a ship
        /// </summary>
        public double ShipBuildTime
        {
            get { return shipBuildTime; }
            set 
            {
                if (value >= 0)
                    shipBuildTime = value;
            }
        }

        /// <summary>
        /// The amount of time spent on the current ship being built
        /// </summary>
        public double BuildTimer
        {
            get { return buildTimer; }
        }

        /// <summary>
        /// The maximum amount of ships that may be queue for building
        /// </summary>
        public int MaxQueueCount
        {
            get { return maxQueue; }
            set
            {
                if (value > 0)
                    maxQueue = value;
            }
        }

        /// <summary>
        /// The build queue
        /// </summary>
        public Queue<ShipOrder> BuildQueue
        {
            get { return buildQueue; }
        }

        #endregion

        #region CONSTRUCTORS

        /// <summary>
        /// Default constructor
        /// </summary>
        public Carrier()
        {
            Type = "Carrier";
            //TurningSpeed = Convert.ToSingle(Math.PI) / 1024f;
            Dimensions = new Size(256, 256);
            Radius = 128f;
            Image = "../Resources/images/ships/carrier.png";
            ImageDimensions = new Size(256, 256);
            Armor = 10000;
            Shield = MaxShield = 3000;
            Energy = MaxEnergy = 3000;
            Cargo = 3000;
            EnergyRegeneration = 0;
            MaxSpeed = 25;
            MaxQueueCount = 5;
            ShipBuildTime = 1.5;
            buildTimer = 0;
            buildQueue = new Queue<ShipOrder>(5);
            POI = new BaseObject();
            POI.DXColor = new Microsoft.DirectX.Direct3D.ColorValue(0f, 1f, 0f, .5f);
            POI.Image = "../Resources/images/effects/poi.png";
            POI.ImageDimensions = new Size(32, 32);
            POI.Dimensions = new Size(50, 50);
            PointOfInterest = new Microsoft.DirectX.Vector3(Rendering.WorldSize.X / 2f, Rendering.WorldSize.Y / 2, 0);
        }

        #endregion

        #region INTERFACE METHODS

        /// <summary>
        /// Adds the specified ship type to the build queue if a slot is available
        /// </summary>
        /// <param name="ship">the type of ship to add to the build queue</param>
        public void BuildShipofType(SHIPTYPES ship, int costModifier)
        {
            if (buildQueue.Count < MaxQueueCount)
            {
                switch (ship)
                {
                    case SHIPTYPES.FIGHTER:
                        if (Cargo >= 25 * costModifier && Energy >= 5f * costModifier)
                        {
                            buildQueue.Enqueue(new ShipOrder(ship, costModifier));
                            Cargo -= (uint)(25 * costModifier);
                            Energy -= 5f * costModifier;
                        }
                        break;
                    case SHIPTYPES.SCOUT:
                        if (Cargo >= 15 * costModifier && Energy >= 15f * costModifier)
                        {
                            buildQueue.Enqueue(new ShipOrder(ship, costModifier));
                            Cargo -= (uint)(15 * costModifier);
                            Energy -= 15f * costModifier;
                        }
                        break;
                    case SHIPTYPES.WORKER:
                        if (Cargo >= 5 * costModifier && Energy >= 25f * costModifier)
                        {
                            buildQueue.Enqueue(new ShipOrder(ship, costModifier));
                            Cargo -= (uint)(5 * costModifier);
                            Energy -= 25f * costModifier;
                        }
                        break;
                }
            }
        }

        /// <summary>
        /// Updates this carrier
        /// </summary>
        /// <param name="delta">change in time since last Update call (in seconds)</param>
        public override void Update(float delta)
        {
            if (!GoToPointOfInterest)
            {
                Microsoft.DirectX.Vector3 velocityWithFriction = new Microsoft.DirectX.Vector3();
                velocityWithFriction = Velocity;
                velocityWithFriction.Scale(.95f);
                if (velocityWithFriction.LengthSq() < 1f)
                    velocityWithFriction.X = velocityWithFriction.Y = velocityWithFriction.Z;
                Velocity = velocityWithFriction;
            }
            else
            {
                Microsoft.DirectX.Vector3 accumulator = new Microsoft.DirectX.Vector3();
                accumulator = PointOfInterest - Position;
                accumulator.Normalize();
                accumulator.Scale(MaxSpeed * delta);
                Velocity += accumulator;
            }
            base.Update(delta);
            if (this.Collide(POI))
                goToPointOfInterest = false;
            if(buildQueue.Count > 0 && QueueStatus == QUEUESTATUS.BUILDING)
                buildTimer += delta;
        }

        /// <summary>
        /// Renders this carrier and the point of interest assigned to the carrier
        /// </summary>
        /// <param name="sprite">DirectX sprite object to use for rendering</param>
        public override void Render(Microsoft.DirectX.Direct3D.Sprite sprite)
        {
            if (GoToPointOfInterest)
                POI.Render(sprite);
            base.Render(sprite);
        }

        /// <summary>
        /// Removes the first queued order from the build queue
        /// </summary>
        /// <param name="amountBuilt">out param: the number of ships that was ordered</param>
        /// <returns>a ship representing the dequeued order</returns>
        /// <remarks>invoke the Clone method on the returned ship to generate the required number of ships of the order</remarks>
        public Ship DequeueShip(out int amountBuilt)
        {
            Ship returnval = null;
            amountBuilt = 0;
            if (QueueStatus == QUEUESTATUS.SHIPREADY)
            {
                ShipOrder dequeuedOrder = buildQueue.Dequeue();
                switch (dequeuedOrder.shipType)
                {
                    case SHIPTYPES.FIGHTER:
                        returnval = new Fighter();
                        break;
                    case SHIPTYPES.SCOUT:
                        returnval = new Scout();
                        break;
                    case SHIPTYPES.WORKER:
                        returnval = new Worker();
                        break;
                }
                returnval.Position = Position;
                buildTimer = 0;
                amountBuilt = dequeuedOrder.amountToBuild;
            }
            return returnval;
        }

        /// <summary>
        /// Removes the last queued ship from the build queue, if exists
        /// </summary>
        public void CancelLastBuild()
        {
            if (buildQueue.Count > 0)
            {
                Queue<ShipOrder> temp = new Queue<ShipOrder>(5);
                while (buildQueue.Count != 1)
                    temp.Enqueue(buildQueue.Dequeue());
                ShipOrder last = buildQueue.Dequeue();
                switch (last.shipType)
                {
                    case SHIPTYPES.FIGHTER:
                        Cargo += (uint)(25 * last.amountToBuild);
                        Energy += 5f * last.amountToBuild;
                        break;
                    case SHIPTYPES.SCOUT:
                        Cargo += (uint)(15 * last.amountToBuild);
                        Energy += 15f * last.amountToBuild;
                        break;
                    case SHIPTYPES.WORKER:
                        Cargo += (uint)(5 * last.amountToBuild);
                        Energy += 25f * last.amountToBuild;
                        break;
                }
                buildQueue = temp;
                if(buildQueue.Count == 0)
                    buildTimer = 0;
            }
        }

        #endregion
    }

    public struct ShipOrder
    {
        public Carrier.SHIPTYPES shipType;
        public int amountToBuild;

        public ShipOrder(Carrier.SHIPTYPES shipType, int amountToBuild)
        {
            this.shipType = shipType;
            this.amountToBuild = amountToBuild;
        }
    }
}
